<!--
 * hi-countdown - 倒计时
 *
 * @author 济南晨霜信息技术有限公司
 * @mobile 18560000860 / 18754137913
 -->
<template>
    <view class="hi-countdown" :class="_classes" :style="_styles">
        <view class="hi-countdown__content" v-if="isEnd && tips">
            <slot name="end">
                {{ tips }}
            </slot>
        </view>
        <view class="hi-countdown__content" v-else>
            <slot>
                <!-- 周 -->
                <view class="hi-countdown__number hi-countdown__number--weeks" v-if="isWeeks">
                    <slot name="weeks" :number="weeks" :countdown="countdown" :show="isWeeks">{{ weeks }}</slot>
                </view>
                <view class="hi-countdown__separator hi-countdown__separator--weeks" v-if="isWeeks">
                    <slot name="weeksSeparator" :separator="separatorWeeks">{{ separatorWeeks }}</slot>
                </view>

                <!-- 天 -->
                <view class="hi-countdown__number hi-countdown__number--days" v-if="isDays">
                    <slot name="days" :number="days" :countdown="countdown" :show="isDays">{{ days }}</slot>
                </view>
                <view class="hi-countdown__separator hi-countdown__separator--days" v-if="isDays">
                    <slot name="daysSeparator" :separator="separatorDays">{{ separatorDays }}</slot>
                </view>

                <!-- 小时 -->
                <view class="hi-countdown__number hi-countdown__number--hours" v-if="isHours">
                    <slot name="hours" :number="hours" :countdown="countdown" :show="isHours">{{ hours }}</slot>
                </view>
                <view class="hi-countdown__separator hi-countdown__separator--hours" v-if="isHours">
                    <slot name="hoursSeparator" :separator="separatorHours">{{ separatorHours }}</slot>
                </view>

                <!-- 分钟 -->
                <view class="hi-countdown__number hi-countdown__number--minutes" v-if="isMinutes">
                    <slot name="minutes" :number="minutes" :countdown="countdown" :show="isMinutes">{{ minutes }}</slot>
                </view>
                <view class="hi-countdown__separator hi-countdown__separator--minutes" v-if="isMinutes">
                    <slot name="minutesSeparator" :separator="separatorMinutes">{{ separatorMinutes }}</slot>
                </view>

                <!-- 秒 -->
                <view class="hi-countdown__number hi-countdown__number--seconds" v-if="isSeconds">
                    <slot name="seconds" :number="seconds" :countdown="countdown" :show="isSeconds">{{ seconds }}</slot>
                </view>
                <view class="hi-countdown__separator hi-countdown__separator--seconds" v-if="isSeconds">
                    <slot name="secondsSeparator" :separator="separatorSeconds">{{ separatorSeconds }}</slot>
                </view>

                <!-- 毫秒 -->
                <view class="hi-countdown__number hi-countdown__number--milliseconds" v-if="isMilliseconds">
                    <slot name="milliseconds" :number="milliseconds" :countdown="countdown" :show="isMilliseconds">{{ milliseconds }}</slot>
                </view>
                <view class="hi-countdown__separator hi-countdown__separator--seconds" v-if="isMilliseconds">
                    <slot name="millisecondsSeparator" :separator="separatorMilliseconds">{{ separatorMilliseconds }}</slot>
                </view>
            </slot>
        </view>
    </view>
</template>

<!-- 由于 HbuilderX 不支持 defineOptions() 写法，故只能在此处进行配置 -->
<script>
    export default { options: uni?.$hi?.config?.componentsOptions || {} };
</script>

<script setup>
    import { ref, computed, onMounted, onBeforeUnmount, watch } from "vue";
    import props from "./props.js";
    import { dateGet, dateGetCountdownData } from "../../functions";

    // 组件属性
    const _props = defineProps(props);

    // 组件事件
    const _emits = defineEmits(["change", "end"]);

    // 组件类名
    const _classes = computed(() => {
        const classes = [];

        // 主题
        if (_props.theme) classes.push(`hi-countdown--theme hi-countdown--theme-${_props.theme}`);

        // 镂空
        if (_props.plain) classes.push("hi-countdown--plain");

        // 浅化背景
        if (_props.tint) classes.push("hi-countdown--tint");

        // 边框
        if (_props.border) classes.push("hi-countdown--border");

        // 数字主题
        if (_props.numTheme) classes.push(`hi-countdown--number-theme hi-countdown--number-theme-${_props.numTheme}`);

        // 数字镂空
        if (_props.numPlain) classes.push("hi-countdown--number-plain");

        // 数字浅化背景
        if (_props.numTint) classes.push("hi-countdown--number-tint");

        // 数字边框
        if (_props.numBorder) classes.push("hi-countdown--number-border");

        return classes;
    });

    // 组件样式
    const _styles = computed(() => {
        const styles = [];

        // 主题
        if (_props.theme) styles.push(`--hi-countdown-theme: var(--hi-theme-${_props.theme})`);

        // 浅化透明度
        if (_props.tintOpacity) styles.push(`--hi-countdown-background-opacity: ${_props.tintOpacity}`);

        // 背景
        if (_props.bg) styles.push(`--hi-countdown-background: ${_props.bg}`);

        // 圆角
        if (_props.radius) styles.push(`--hi-countdown-border-radius: ${_props.radius}`);

        // 文字颜色
        if (_props.color) styles.push(`--hi-countdown-color: ${_props.color}`);

        // 文字大小
        if (_props.fontSize) styles.push(`--hi-countdown-font-size: ${_props.fontSize}px`);

        // 文字粗细
        if (_props.fontWeight) styles.push(`--hi-countdown-font-weight: ${_props.fontWeight}`);

        // 间距
        if (_props.gap) styles.push(`--hi-countdown-gap: ${_props.gap}`);

        // 内间距
        if (_props.padding) styles.push(`--hi-countdown-padding: ${_props.padding}`);

        // 数字大小
        if (_props.numFontSize) styles.push(`--hi-countdown-number-font-size: ${_props.numFontSize}`);

        // 数字颜色
        if (_props.numColor) styles.push(`--hi-countdown-number-color: ${_props.numColor}`);

        // 数字粗细
        if (_props.numFontWeight) styles.push(`--hi-countdown-number-font-weight: ${_props.numFontWeight}`);

        // 数字宽度
        if (_props.numWidth) styles.push(`--hi-countdown-number-width: ${_props.numWidth}`);

        // 数字高度
        if (_props.numHeight) styles.push(`--hi-countdown-number-height: ${_props.numHeight}`);

        // 数字圆角
        if (_props.numRadius) styles.push(`--hi-countdown-number-border-radius: ${_props.numRadius}`);

        // 数字边框颜色
        if (_props.numBorderColor) styles.push(`--hi-countdown-number-border-color: ${_props.numBorderColor}`);

        // 数字边框粗细
        if (_props.numBorderWidth) styles.push(`--hi-countdown-number-border-width: ${_props.numBorderWidth}`);

        // 数字边框样式
        if (_props.numBorderStyle) styles.push(`--hi-countdown-number-border-style: ${_props.numBorderStyle}`);

        // 数字内边距
        if (_props.numPadding) styles.push(`--hi-countdown-number-padding: ${_props.numPadding}`);

        // 数字主题
        if (_props.numTheme) styles.push(`--hi-countdown-number-theme: var(--hi-theme-${_props.numTheme})`);

        // 数字浅化透明度
        if (_props.numTintOpacity) styles.push(`--hi-countdown-number-background-opacity: ${_props.numTintOpacity}`);

        return styles;
    });

    // 倒计时数据
    const countdown = ref({
        weeks: 0,
        days: 0,
        hours: 0,
        minutes: 0,
        seconds: 0,
        milliseconds: 0
    });

    // 是否结束
    const isEnd = computed(() => {
        if (
            countdown.value.weeks <= 0 &&
            countdown.value.days <= 0 &&
            countdown.value.hours <= 0 &&
            countdown.value.minutes <= 0 &&
            countdown.value.seconds <= 0 &&
            countdown.value.milliseconds <= 0
        ) {
            countdown.value = {
                weeks: 0,
                days: 0,
                hours: 0,
                minutes: 0,
                seconds: 0,
                milliseconds: 0
            };
            _emits("end");
            clearInterval(timer);
            return true;
        }
        return false;
    });

    // 倒计时数据级别
    const countdownLevel = computed(() => {
        // 获取倒计时数据级别
        let level = "day";

        // 判断是否是周级别
        if (_props.format.includes("{WW}") || _props.format.includes("{W}")) level = "week";
        // 判断是否是天级别
        else if (_props.format.includes("{DD}") || _props.format.includes("{D}")) level = "day";
        // 判断是否是小时级别
        else if (_props.format.includes("{HH}") || _props.format.includes("{H}")) level = "hour";
        // 判断是否是分钟级别
        else if (_props.format.includes("{MM}") || _props.format.includes("{M}")) level = "minute";
        // 判断是否是秒级别
        else if (_props.format.includes("{SS}") || _props.format.includes("{S}")) level = "second";
        // 判断是否是毫秒级别
        else if (_props.format.includes("{MSS}") || _props.format.includes("{MS}")) level = "millisecond";

        return level;
    });

    // 是否显示
    const isWeeks = computed(() => _props.format.includes("{WW}") || _props.format.includes("{W}")); // 周
    const isDays = computed(() => _props.format.includes("{DD}") || _props.format.includes("{D}")); // 天
    const isHours = computed(() => _props.format.includes("{HH}") || _props.format.includes("{H}")); // 小时
    const isMinutes = computed(() => _props.format.includes("{MM}") || _props.format.includes("{M}")); // 分钟
    const isSeconds = computed(() => _props.format.includes("{SS}") || _props.format.includes("{S}")); // 秒
    const isMilliseconds = computed(() => _props.format.includes("{MSS}") || _props.format.includes("{MS}")); // 毫秒

    // 显示的周数字
    const weeks = computed(() => {
        if (_props.format.includes("{WW}")) return countdown.value.weeks.toString().padStart(2, "0");
        return countdown.value.weeks;
    });

    // 显示的天数字
    const days = computed(() => {
        if (_props.format.includes("{DD}")) return countdown.value.days.toString().padStart(2, "0");
        return countdown.value.days;
    });

    // 显示的小时数字
    const hours = computed(() => {
        if (_props.format.includes("{HH}")) return countdown.value.hours.toString().padStart(2, "0");
        return countdown.value.hours;
    });

    // 显示的分钟数字
    const minutes = computed(() => {
        if (_props.format.includes("{MM}")) return countdown.value.minutes.toString().padStart(2, "0");
        return countdown.value.minutes;
    });

    // 显示的秒数字
    const seconds = computed(() => {
        if (_props.format.includes("{SS}")) return countdown.value.seconds.toString().padStart(2, "0");
        return countdown.value.seconds;
    });

    // 显示的毫秒数字
    const milliseconds = computed(() => {
        if (_props.format.includes("{MSS}")) return countdown.value.milliseconds.toString().padStart(3, "0");
        return parseInt(countdown.value.milliseconds / 10)
            .toString()
            .padStart(2, "0");
    });

    // 周分隔符
    const separatorWeeks = computed(() => {
        const regex = /\{W(W)?\}([\s\S]*?)\{D(D)?\}/;
        const match = _props.format.match(regex);
        if (match) return match[2];
        return "周";
    });

    // 天分隔符
    const separatorDays = computed(() => {
        const regex = /\{D(D)?\}([\s\S]*?)\{H(H)?\}/;
        const match = _props.format.match(regex);
        if (match) return match[2];
        return "天";
    });

    // 小时分隔符
    const separatorHours = computed(() => {
        const regex = /\{H(H)?\}([\s\S]*?)\{M(M)?\}/;
        const match = _props.format.match(regex);
        if (match) return match[2];
        return "小时";
    });

    // 分钟分隔符
    const separatorMinutes = computed(() => {
        const regex = /\{M(M)?\}([\s\S]*?)\{S(S)?\}/;
        const match = _props.format.match(regex);
        if (match) return match[2];
        return "分钟";
    });

    // 秒分隔符
    const separatorSeconds = computed(() => {
        const regex = /\{S(S)?\}([\s\S]*?)\{MS(MS)?\}/;
        const match = _props.format.match(regex);
        if (match) return match[2];
        return "秒";
    });

    // 毫秒分隔符
    const separatorMilliseconds = computed(() => {
        const regex = /\{MS(S)?\}(.*)/;
        const match = _props.format.match(regex);
        if (match) return match[2];
        return "";
    });

    // 倒计时定时器
    let timer = null;

    // 监听结束时间
    watch(
        () => _props.date,
        (newVal) => {
            // 转成 Date 对象
            const endDate = dateGet(newVal);
            if (endDate) startCountdown(endDate);
        },
        { immediate: true }
    );

    // 组件卸载之前清除定时器
    onBeforeUnmount(() => {
        clearTimer();
    });

    // 开始倒计时
    function startCountdown() {
        countdown.value = dateGetCountdownData(_props.date, countdownLevel.value);
        _emits("change", countdown.value);
        timer = setInterval(() => {
            countdown.value = dateGetCountdownData(_props.date, countdownLevel.value);
            _emits("change", countdown.value);
        }, _props.interval);
    }

    /**
     * 清除定时器
     */
    function clearTimer() {
        if (timer) {
            clearInterval(timer);
            timer = null;
        }
    }
</script>

<style lang="scss" scoped>
    .hi-countdown {
        background: var(--hi-countdown-background, none);
        border-radius: var(--hi-countdown-border-radius, 3px);
        color: var(--hi-countdown-color, inherit);
        font-size: var(--hi-countdown-font-size, inherit);
        font-weight: var(--hi-countdown-font-weight, inherit);
        display: var(--hi-countdown-display, inline-flex);
        padding: var(--hi-countdown-padding, 0);
        border: var(--hi-countdown-border-width, 0) var(--hi-countdown-border-style, solid)
            var(--hi-countdown-border-color, var(--hi-countdown-theme, currentColor));
        position: var(--hi-countdown-position, relative);

        &__content {
            display: var(--hi-countdown-content-display, flex);
            gap: var(--hi-countdown-gap, 3px);
            align-items: var(--hi-countdown-content-align-items, center);
            position: var(--hi-countdown-content-position, relative);
            z-index: var(--hi-countdown-content-z-index, 2);
        }

        &__number {
            font-size: var(--hi-countdown-number-font-size, inherit);
            color: var(--hi-countdown-number-color, inherit);
            font-weight: var(--hi-countdown-number-font-weight, inherit);
            width: var(--hi-countdown-number-width, auto);
            height: var(--hi-countdown-number-height, auto);
            border-radius: var(--hi-countdown-number-border-radius, 3px);
            border: var(--hi-countdown-number-border-width, 0) var(--hi-countdown-number-border-style, solid)
                var(--hi-countdown-number-border-color, var(--hi-countdown-number-theme, currentColor));
            display: var(--hi-countdown-number-display, flex);
            align-items: var(--hi-countdown-number-align-items, center);
            justify-content: var(--hi-countdown-number-justify-content, center);
            text-align: var(--hi-countdown-number-text-align, center);
            background: var(--hi-countdown-number-background, none);
            padding: var(--hi-countdown-number-padding, 0);
            position: var(--hi-countdown-number-position, relative);
        }

        // 边框
        &--border {
            border-width: var(--hi-countdown-border-width, 1px);
            padding: var(--hi-countdown-padding, 5px 10px);
        }

        // 主题
        &--theme {
            background: var(--hi-countdown-background, var(--hi-countdown-theme, none));
            color: var(--hi-countdown-color, #ffffff);
            padding: var(--hi-countdown-padding, 5px 10px);
        }

        // 镂空
        &--plain {
            background: var(--hi-countdown-background, transparent);
            color: var(--hi-countdown-color, var(--hi-countdown-theme, inherit));
            border-width: var(--hi-countdown-border-width, 1px);
        }

        // 浅化
        &--tint {
            background: transparent;
            color: var(--hi-countdown-color, var(--hi-countdown-theme, inherit));

            &::before {
                content: "";
                position: absolute;
                width: 100%;
                height: 100%;
                left: 0;
                top: 0;
                z-index: 0;
                background: var(--hi-countdown-background, var(--hi-countdown-theme, currentColor));
                opacity: var(--hi-countdown-background-opacity, 0.2);
                border-radius: inherit;
            }
        }

        // 数字边框
        &--number-border {
            .hi-countdown__number {
                border-width: var(--hi-countdown-number-border-width, 1px);
                padding: var(--hi-countdown-number-padding, 3px 6px);
            }
        }

        // 数字主题
        &--number-theme {
            .hi-countdown__number {
                background: var(--hi-countdown-number-background, var(--hi-countdown-number-theme, none));
                color: var(--hi-countdown-number-color, #ffffff);
                padding: var(--hi-countdown-number-padding, 3px 6px);
            }
        }

        // 数字镂空
        &--number-plain {
            .hi-countdown__number {
                background: var(--hi-countdown-number-background, transparent);
                color: var(--hi-countdown-number-color, var(--hi-countdown-number-theme, inherit));
                padding: var(--hi-countdown-number-padding, 3px 6px);
                border-width: var(--hi-countdown-number-border-width, 1px);
            }
        }

        // 数字浅化
        &--number-tint {
            .hi-countdown__number {
                background: transparent;
                color: var(--hi-countdown-number-color, var(--hi-countdown-number-theme, inherit));

                &::before {
                    content: "";
                    position: absolute;
                    width: 100%;
                    height: 100%;
                    left: 0;
                    top: 0;
                    z-index: 0;
                    background: var(--hi-countdown-number-background, var(--hi-countdown-number-theme, currentColor));
                    opacity: var(--hi-countdown-number-background-opacity, 0.2);
                    border-radius: inherit;
                }
            }
        }
    }
</style>
